package repositories

import (
	"log"

	"gitee.com/yanxingshuyuan/backend/server/models"
	"github.com/jmoiron/sqlx"
)

type PeopleRepo struct {
	DB *sqlx.DB
}

func NewPeopleRepo(db *sqlx.DB) *PeopleRepo {
	return &PeopleRepo{
		DB: db,
	}
}

func (r *PeopleRepo) AddPerson(person *models.PersonForm) bool {
	var id string
	tx, err := r.DB.Beginx()
	rs, err := tx.NamedQuery("INSERT INTO people (fullname, othernames, intro, avatar) VALUES (:fullname, :othernames, :intro, :avatar) ON CONFLICT DO NOTHING RETURNING id", &person)
	if err != nil {
		log.Printf("Error inserting person: %#v, with error: %v\n", person, err)
		tx.Rollback()
		return false
	}
	rs.Next()
	rs.Scan(&id)
	log.Printf("person added:%v\n", id)
	person.ID = id
	rs.Close()

	if !r.updatePersonTags(person, tx) {
		tx.Rollback()
		return false
	}
	tx.Commit()
	return true
}

func (r *PeopleRepo) updatePersonTags(person *models.PersonForm, tx *sqlx.Tx) bool {
	var tagids []int

	for i := range person.Tags {
		tagids = append(tagids, person.Tags[i].ID)
	}

	// 先添加新ID，如果已经存在，可以忽略
	for i := range tagids {
		tid := tagids[i]
		_, err := tx.Exec("INSERT INTO people_tags VALUES ($1, $2) ON CONFLICT DO NOTHING", person.ID, tid)
		if err != nil {
			log.Printf("Error inserting new tags:[%v] %v\n", tid, err)
		}
	}

	// 再删除多余的tid
	if len(tagids) == 0 {
		_, err := tx.Exec("DELETE from people_tags where pid = $1", person.ID)
		if err != nil {
			log.Printf("error delete redundent tag for person:[%v], erro: %v\n", person.ID, err)
			return false
		}
	} else {
		query, args, err := sqlx.In("DELETE from people_tags where pid = ? and tid not in (?)", person.ID, tagids)
		if err != nil {
			log.Printf("error making in query to update person tag:%v\n", err)
			return false
		}

		query = r.DB.Rebind(query)
		_, err = tx.Exec(query, args...)
		if err != nil {
			log.Printf("error delete redundent tags for person:[%v,%#v],%v\n", person.ID, tagids, err)
			return false
		}
	}
	return true
}

func (r *PeopleRepo) ModifyPerson(personForm *models.PersonForm) bool {
	tx, err := r.DB.Beginx()
	log.Printf("Got forms: %#v,\n", personForm.Tags)
	_, err = tx.NamedExec("UPDATE people set fullname = :fullname, othernames = :othernames, intro = :intro, avatar = :avatar where id = :id", &personForm)
	if err != nil {
		log.Printf("Error modifying person: %#v, with error: %v\n", personForm, err)
		tx.Rollback()
		return false
	}

	if !r.updatePersonTags(personForm, tx) {
		tx.Rollback()
		return false
	}

	tx.Commit()
	return true
}

func (r *PeopleRepo) ListPeople() (people []models.Person) {
	err := r.DB.Select(&people, "SELECT id, fullname, othernames, intro, avatar from people where active = true order by fullname")
	if err != nil {
		log.Printf("Error listing people, with error:%v\n", err)
	}
	return people
}

func (r *PeopleRepo) GetPerson(pid string) (person models.PersonForm) {
	err := r.DB.Get(&person, "SELECT id, fullname, othernames, intro, avatar from people where id = $1", pid)
	if err != nil {
		log.Printf("Error listing people, with error:%v\n", err)
	}

	var tags []models.Tag
	r.DB.Select(&tags, "SELECT t.* from tags t, people_tags pt where t.id = pt.tid and pt.pid = $1", pid)
	if len(tags) > 0 {
		person.Tags = tags
	}
	return person
}

func (r *PeopleRepo) GetOrAddPerson(name string, intro string) (person models.PersonForm) {
	err := r.DB.Get(&person, "SELECT id, fullname, othernames, intro, avatar from people where fullname = $1 limit 1", name)
	if err != nil {
		// 如果查找不到，说明此人不存在，需要新建一条数据
		log.Printf("Person not found, creating one:%v, err: %v\n", name, err)

		_, err = r.DB.Exec("INSERT INTO people (fullname, intro) VALUES ($1, $2)", name, intro)
		if err != nil {
			log.Printf("Error creating person:%v\n", err)
			return
		}
		err = r.DB.Get(&person, "SELECT id, fullname, othernames, intro, avatar from people where fullname = $1 limit 1", name)
		if err != nil {
			log.Printf("Error creating person:%v\n", err)
			return
		}
	}

	var tags []models.Tag
	r.DB.Select(&tags, "SELECT t.* from tags t, people_tags pt where t.id = pt.tid and pt.pid = $1", name)
	if len(tags) > 0 {
		person.Tags = tags
	}
	return person
}

func (r *PeopleRepo) HotAuthors(tag string) (people []models.Person) {
	var tagid string
	err := r.DB.Get(&tagid, "SELECT id from tags where cat = $1 and val = $2", models.TagCatPeople, tag)
	if err != nil {
		log.Printf("Error finding tag %v, with error:%v\n", tag, err)
		return people
	}
	log.Printf("found tag id %v for tag name: %v", tagid, tag)
	err = r.DB.Select(&people, "SELECT id, fullname, othernames, intro, avatar from people p, people_tags pt where active = true and pt.pid = p.id and pt.tid = $1 order by fullname", tagid)
	if err != nil {
		log.Printf("Error listing people, with error:%v\n", err)
	}
	return people
}
